package com.fitz.cluster;

import com.fitz.proxy.RpcReferenceBean;
import com.fitz.registry.InstanceInfo;
import com.fitz.remote.client.ConsumerClient;
import com.fitz.remote.model.RpcRequest;
import com.fitz.remote.model.RpcResponse;
import com.fitz.util.ListUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @author fitz 2020-5-21 16:16
 */

public class FailoverStrategy extends AbstractClusterStrategy {

    private static final Logger logger = LoggerFactory.getLogger(FailoverStrategy.class);

    @Override
    public RpcResponse call(RpcRequest rpcRequest, RpcReferenceBean referenceBean) {
        List<InstanceInfo> dataList = referenceBean.getInstanceRegistry().getAllInstances(referenceBean.getInterfaceName());
        List<InstanceInfo> serverList =  ListUtil.deepCopy(dataList);
        return process(serverList,rpcRequest,referenceBean);
    }

    private RpcResponse process(List<InstanceInfo> serverList,RpcRequest rpcRequest,RpcReferenceBean referenceBean){
        InstanceInfo instance = discoveryNext(serverList,referenceBean);
        logger.info("discoveryNext:[{}]",instance);
        if (serverList.size() > 1){
            serverList.remove(instance);
        }
        ConsumerClient client = getClient(referenceBean);
        RpcResponse rpcResponse = new RpcResponse();
        if (client == null){
            rpcResponse.setErrorMessage("remote call error");
            rpcResponse.setRequestId(rpcRequest.getRequestId());
            return rpcResponse;
        }
        try {
            rpcResponse = sendRequest(rpcRequest,client);
            logger.info(rpcResponse.toString());
            if (StringUtils.isNotBlank(rpcResponse.getErrorMessage())){
                int retry = referenceBean.getRetry();
                if (retry > 0){
                    retry -= 1;
                    referenceBean.setRetry(retry);
                    rpcRequest.setCreateTime(System.currentTimeMillis());
                    rpcResponse = process(serverList,rpcRequest,referenceBean);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            rpcResponse.setErrorMessage("remote call error");
            rpcResponse.setRequestId(rpcRequest.getRequestId());
        }finally {
            returnClient(client);
        }
        return rpcResponse;
    }

    /**
     * 获取下一个服务节点
     * @param serverList
     * @param referenceBean
     * @return
     */
    private InstanceInfo discoveryNext(List<InstanceInfo> serverList, RpcReferenceBean referenceBean){
        return referenceBean.getInstanceRegistry().discover(referenceBean.getLoadBalance(),serverList);
    }
}
